package edu.mercer.sse.ldap;

import edu.mercer.sse.app.Config;

import java.sql.SQLException;
import java.util.Map;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.UnmodifiableIterator;

import edu.mercer.sse.database.DB2LDAPLayout;
import edu.mercer.sse.database.DBRecordSet;
import edu.mercer.sse.errors.CriticalException;
import edu.mercer.sse.errors.CustomLogger;
import edu.mercer.sse.errors.ErrorLoggingVisitor;
import edu.mercer.sse.errors.LoggerCustom;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Show LDAP entries to be deleted.<p>
 * 
 * Input: <b>LDAP entry</b>. Compared to database entries. <b>Do not</b> 
 * 	provide database entries to this Predicate; i.e., is one-way comparison.
 *  <p>
 * 
 * Report which LDAP entries are not present in database, as in database->LDAP 
 * 	layout data synchronization/publishing.<p>
 *
 * @see DB2LDAPLayout
 * 
 * @see Predicate
 */

public class LDAPDeletePredicate implements 

		Predicate<Map<String,String>>
{
	private static final CustomLogger _log = LoggerCustom.obtainLog( 
			
			"LDAPDeletePredicate", 
				
			Config.getLogLevel());	
	
	/**
	 * No-arg constructor.<p>
	 * 
	 * Show LDAP entries to be deleted.<p>
	 * 
	 * Input: <b>LDAP entry</b>. Compared to database entries. <u>Do not 
	 * 	provide database entries to this Predicate.</u><p>
	 * 
	 * Report which LDAP entries are not present in database, as in 
	 * 	database->LDAP layout data synchronization/publishing.<p>
	 * 
	 * @see DB2LDAPLayout
	 * 
	 * @see Predicate
	 */
	
	public LDAPDeletePredicate(){}


	@Override
	public boolean apply( final Map<String, String> ldapEntry )
	{
		try
		{
			checkNotNull( ldapEntry, "null ldap entry, expect ImmutableMap " +
					"<String, String>" );

			checkArgument( ldapEntry.size() > 0, "empty ImmutableMap ldap " +
					"entry" );
			
			final String uid = Config.settings()
							   		 .getProperty("ldap-member-id");
			
			checkArgument( uid.length() > 0, "empty ldap-member-id in " 
					+ "configuration" );
			
			final String dbUserField = DB2LDAPLayout.getLayout()
					.inverse()
					.get( uid );

			checkNotNull( dbUserField, "null database user field, require"
					+ " database field corresponding to to ldap: " + uid );

			final UnmodifiableIterator<ImmutableMap<String,String>> dbData = 
					DBRecordSet.getData().iterator();

			checkArgument( dbData.hasNext(), "failed to retrieve any database" 
					+ " records" );

			Boolean foundLdapEntryInDatabase = false;
			
			while( dbData.hasNext() )
			{
				ImmutableMap<String,String> dbRecord = dbData.next(); 

				if( dbRecord.containsKey( dbUserField ) && 
						dbRecord.get( dbUserField )
								.equals( ldapEntry.get( uid ) ) )
				{
					foundLdapEntryInDatabase = true;
					break;
					
				}//if

			}//while
			
			if( ! foundLdapEntryInDatabase )
			{
				_log.fine( "ldap entry not found in db: " 
						+ ldapEntry.get( uid ) );
				
			}//if
			
			return ! foundLdapEntryInDatabase;
					
		}
		catch( final SQLException err )
		{
			final CriticalException errWrapped = new CriticalException( err );
			errWrapped.accept( new ErrorLoggingVisitor() );
			
			return true;	// default is not to delete
			
		}//try
		
	}//method
	

}//class
